#include <iostream>
#include <algorithm>

#include <windows.h>
#include <psapi.h>

#undef min	// that's really disgusting

void print_process_name(HANDLE process)
{
	char process_name[1024];
	if (GetProcessImageFileName(process, process_name, 1024))
	{
		std::cout << " " << process_name;
	}
	else
	{
		std::cout << " " << "<unknown>";
	}
}

void print_process_memusage(HANDLE process)
{
	PROCESS_MEMORY_COUNTERS memory_counters;
	if (GetProcessMemoryInfo(process, &memory_counters, sizeof(memory_counters)))
	{
		const size_t Kb = 1024;
		std::cout << " "
					<< memory_counters.PeakWorkingSetSize/Kb
					<< "Kb "
					<< memory_counters.WorkingSetSize/Kb
					<< "Kb "
					<< memory_counters.PeakPagefileUsage/Kb
					<< "Kb "
					<< memory_counters.PagefileUsage/Kb
					<< "Kb ";
	}
}

void print_module_filename(HANDLE process, HMODULE module)
{
	const DWORD max_module_name_length = 1024;
	char module_name[max_module_name_length];
	
	if (GetModuleFileNameEx(process, module, module_name, max_module_name_length))
	{
		std::cout << "\t" << module_name;
	}
	else
	{
		std::cout << "\t" << "<unknown>";
	}
}

void print_used_modules(HANDLE process)
{
	const DWORD max_module_number = 1024;
	HMODULE modules[max_module_number];

	DWORD modules_bytes_req;
	if (EnumProcessModules(process, modules, 1024 * sizeof(HMODULE), &modules_bytes_req))
	{
		DWORD modules_number = std::min(DWORD(modules_bytes_req/sizeof(HMODULE)), max_module_number);
		std::cout << "DLLs (" << modules_number << "): " << std::endl;
				
		std::for_each(modules, modules + modules_number, [&](HMODULE module) {					
			print_module_filename(process, module);
			std::cout << std::endl;
		});
		
	}
}

int main(int argc, char **argv)
{
	std::cout << "<Process ID> <Full process file name>"
					" <Peak working set size, Kb> <Working set size, Kb>"
					" <Peak pagefile usage, Kb> <Pagefile usage, Kb>"
				<< std::endl;

	DWORD max_ids_number = 1024;
	DWORD *process_ids = new DWORD[max_ids_number];
	
	DWORD process_ids_bytes_req;
	if (EnumProcesses(process_ids, max_ids_number * sizeof(DWORD), &process_ids_bytes_req))
	{
		DWORD process_ids_number = std::min(DWORD(process_ids_bytes_req/sizeof(DWORD)), max_ids_number);
		std::cout << "Processes (" << process_ids_number << "): " << std::endl;
		std::for_each(process_ids, process_ids + process_ids_number, [](DWORD process_id) {
			std::cout << process_id;

			HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);

			print_process_name(process);
			print_process_memusage(process);

			std::cout << std::endl;

			print_used_modules(process);

			CloseHandle(process);			
		});
	}

	delete[] process_ids;

	return 0;
}
